#include "usart.h"


UART_HandleTypeDef	Uart1Handle;

uint8_t g_isUsart1Init = 0;
struct UsartInitParam g_UsartInitParam = {};

int32_t USART1_Init(const struct UsartInitParam *param) {

    if ( g_isUsart1Init == 1 ) {
        printf( "%s: USART1 has been initialized", __func__ );
        return -1;
    }

    if ( param == NULL ) {
        printf( "%s: param is NULL", __func__);
        return -2;
    }

    g_UsartInitParam = *param;

    if (g_UsartInitParam.gpioPort == GPIOA) {
        __HAL_RCC_GPIOA_CLK_ENABLE();
    } else if (g_UsartInitParam.gpioPort == GPIOB) {
        __HAL_RCC_GPIOB_CLK_ENABLE();
    } else if (g_UsartInitParam.gpioPort == GPIOC) {
        __HAL_RCC_GPIOC_CLK_ENABLE();
    } else {
        printf("%s: UnSupport GPIO Port: %p \r\n", __func__,  g_UsartInitParam.gpioPort);
        return -2;
    }

    GPIO_InitTypeDef Uart_GPIO_InitConfig = {};
    __HAL_RCC_USART1_CLK_ENABLE();
    Uart_GPIO_InitConfig.Pin = g_UsartInitParam.gpioPin;
    Uart_GPIO_InitConfig.Mode = GPIO_MODE_AF_PP;
    Uart_GPIO_InitConfig.Pull = GPIO_PULLUP;
    Uart_GPIO_InitConfig.Speed = GPIO_SPEED_FREQ_HIGH;
    Uart_GPIO_InitConfig.Alternate = GPIO_AF1_USART1;
    HAL_GPIO_Init(g_UsartInitParam.gpioPort, &Uart_GPIO_InitConfig);

    HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);

    Uart1Handle.Instance = USART1;
    Uart1Handle.Init.BaudRate = g_UsartInitParam.BaudRate;
    Uart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
    Uart1Handle.Init.StopBits = UART_STOPBITS_1;
    Uart1Handle.Init.Parity = UART_PARITY_NONE;
    Uart1Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    Uart1Handle.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&Uart1Handle);
    __HAL_UART_ENABLE_IT(&Uart1Handle, UART_IT_RXNE);

    g_isUsart1Init = 1;
    return 0;
}

void USART1_DeInit(void) {
    if ( g_isUsart1Init == 0 ) {
        printf("%s: USART1 has not been initialized", __func__);
        return;
    }

    HAL_UART_DeInit(&Uart1Handle);
    __HAL_RCC_USART1_CLK_DISABLE();
    __HAL_UART_DISABLE_IT(&Uart1Handle, UART_IT_RXNE);
    HAL_NVIC_DisableIRQ(USART1_IRQn);

    if (g_UsartInitParam.gpioPort == GPIOA) {
        __HAL_RCC_GPIOA_CLK_DISABLE();
    } else if (g_UsartInitParam.gpioPort == GPIOB) {
        __HAL_RCC_GPIOB_CLK_DISABLE();
    } else if (g_UsartInitParam.gpioPort == GPIOC) {
        __HAL_RCC_GPIOC_CLK_DISABLE();
    }
    HAL_GPIO_DeInit(g_UsartInitParam.gpioPort, g_UsartInitParam.gpioPin);

    g_isUsart1Init = 0;
}

void USART1_IRQHandler(void) {
    if (__HAL_UART_GET_IT_SOURCE(&Uart1Handle, UART_IT_RXNE)) {
        uint8_t ch = READ_REG(Uart1Handle.Instance->DR);

        WRITE_REG(Uart1Handle.Instance->DR, ch);
    }
}

void USART1_SendString(uint8_t *str) {
    unsigned int k = 0;
    do {
        HAL_UART_Transmit(&Uart1Handle, (uint8_t *) (str + k), 1, 1000);
        k++;
    } while (*(str + k) != '\0');
}

#if (defined (__CC_ARM)) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
/**
  * @brief  writes a character to the usart
  * @param  ch
  *         *f
  * @retval the character
  */
int fputc(int ch, FILE *f)
{
  /* Send a byte to USART */
  HAL_UART_Transmit(&Uart1Handle, (uint8_t *)&ch, 1, 1000);

  return (ch);
}

/**
  * @brief  get a character from the usart
  * @param  *f
  * @retval a character
  */
int fgetc(FILE *f)
{
  int ch;
  HAL_UART_Receive(&Uart1Handle, (uint8_t *)&ch, 1, 1000);
  return (ch);
}

#elif defined(__ICCARM__)
/**
  * @brief  writes a character to the usart
  * @param  ch
  *         *f
  * @retval the character
  */
int putchar(int ch)
{
  /* Send a byte to USART */
  HAL_UART_Transmit(&DebugUartHandle, (uint8_t *)&ch, 1, 1000);

  return (ch);
}
#elif  defined(__GNUC__)
/**
  * @brief  writes a character to the usart
  * @param  ch
  * @retval the character
  */
int __io_putchar(int ch) {
    /* Send a byte to USART */
    HAL_UART_Transmit(&Uart1Handle, (uint8_t *) &ch, 1, 10);

    return ch;
}

int _write(int file, char *ptr, int len) {
    int DataIdx;
    for (DataIdx = 0; DataIdx < len; DataIdx++) {
        __io_putchar(*ptr++);
    }
    return len;
}
#endif
